Serverless Frameworkのプラグインを利用したDead Letter Queueの設定
はじめに
こんにちは、中山です。
今回はServerless Frameworkのプラグインを利用して昨年末に導入されたLambda関数のDead Letter Queueの設定方法をご紹介したいと思います。Dead Letter Queueそのものについては以下のエントリを参照してください。
利用するプラグインはgmetzker/serverless-plugin-lambda-dead-letterです。執筆時点(2017/01/31)ではまだServerless Frameworkのコア機能としてDead Letter Queueがサポートされていません。ちょうどプラグインの作者の方がIssueを上げていますね。恐らく今後コア機能として導入されていくと思いますが、現状Serverless Frameworkを利用しつつDead Letter Queueも使いたい場合このプラグインを利用することになると思います。
なお、本エントリを執筆する上で検証に利用した主要な各種ツールのバージョンは以下の通りです。バージョンによって結果が変更される可能性があるので、その点ご了承ください。
- Serverless Framework: 1.6.0
- serverless-plugin-lambda-dead-letter: 1.2.0
使ってみる
早速使ってみましょう。
インストール
プラグインのインストールは簡単です。Serverless Frameworkで管理しているディレクトリに移動後以下のコマンドを実行するだけです。
$ npm install --save serverless-plugin-lambda-dead-letter
コマンドを実行すると node_modules
というディレクトリにプラグインや依存するモジュールがインストールされます。
SQS
まずはじめにDead Letter Queueの送り先としてSQSを指定してみます。以下のファイルを用意してください。
serverless.yml
frameworkVersion: ">=1.6.0" service: lambda-dlq-sqs-test custom: sqs: LambdaDLQSQSTest provider: name: aws runtime: python2.7 stage: dev region: ap-northeast-1 iamRoleStatements: - Effect: Allow Action: - sqs:SendMessage Resource: - Fn::Join: [ ":", [ "arn:aws:sqs", Ref: "AWS::Region", Ref: "AWS::AccountId", "${self:custom.sqs}" ] ] plugins: - serverless-plugin-lambda-dead-letter functions: fail: handler: handler.fail deadLetter: sqs: ${self:custom.sqs} events: - schedule: rate(1 minute)
ハイライトした点に注目してください。まず iamRoleStatements
プロパティでSQSにメッセージを送信する権限( sqs:SendMessage
)をLambda関数に付与しています。これを指定しないと以下のようなエラーが出力されてしまいます。
Serverless Error --------------------------------------- The provided execution role does not have permissions to call SendMessage on SQS
続いて plugins
プロパティで今回のプラグインを利用することを指定しています。 deadLetter
プロパティでDead Letter Queueの宛先にSQSを指定しています。このプラグインではDead Letter Queueの設定方法を複数用意しているのですが(詳細はREADMEを参照)、今回は宛先の指定と同時にSQSの作成及びパーミッションの設定も行っています。最後に、Lambda関数を1分毎に実行させてキューにメッセージが蓄積されることを確認しやすくしています。
handler.py
def fail(event, context): raise Exception('Exception occured')
Lambda関数は実行を失敗させたいだけなので raise
ですぐに例外を出力させています。
デプロイはいつものように実行するだけです。
$ sls deploy -v Serverless: Creating Stack... Serverless: Checking Stack create progress... <snip>
デプロイ後、暫く待つと以下のようにキューへメッセージが溜まっていくことが確認できます。
$ aws sqs get-queue-attributes \ --queue-url "$(aws sqs get-queue-url \ --queue-name LambdaDLQSQSTest \ --output text)" \ --attribute-names ApproximateNumberOfMessages { "Attributes": { "ApproximateNumberOfMessages": "5" } }
メッセージの中身を見ると以下のようになっています。
$ aws sqs receive-message \ --queue-url "$(aws sqs get-queue-url \ --queue-name LambdaDLQSQSTest \ --output text)" { "Messages": [ { "Body": "{\"version\":\"0\",\"id\":\"4d652e87-c7d6-40bb-b49b-9481e4447ff7\",\"detail-type\":\"Scheduled Event\",\"source\":\"aws.events\",\"account\":\"************\",\"time\":\"2017-01-31T12:57:36Z\",\"region\":\"ap-northeast-1\",\"resources\":[\"arn:aws:events:ap-northeast-1:************:rule/lambda-dlq-sqs-test-dev-FailEventsRuleSchedule1-XO2V37TT4JZY\"],\"detail\":{}}", "ReceiptHandle": "AQEBWGjW4nofI0sR46Pt5L3xiAwEokcEHDOvT4JvYnwIwfUOApd9IDepygarwIwHM+jnXLs1e/FKHQOW/PCTtIwfpIBZgT2gknruuca55QdDsHzu+G8lA9KaR+g0Q8otolTIVWdvi6bcW5fD0fCU6uyPVZFNjBfo8DohhwRVwfonhKxoKBsVbsw+Fpqxh/cyNmB1qZ8r7HXbGv6p/nNAAofCBJwoLITveVvaGCStMTOB1/v7/j5lzF80rFdAb5AhL19xkao55KGL+DGMuGTPlcTF/tkYhUFl39gnk5xaybs+/TTtzAtsBFOc18OaAHQmq6VQWVNyDkGuHBLQfGr+fTwbU10ZJ0Lxl4598aiesb84HzRH7zqIPYpz6qUIKbRkOp2zXV5M1L7suln1aRcZnvhjwg==", "MD5OfBody": "cb56242c6a9c19ae6a0472397b2986c9", "MessageId": "66b735bb-df8e-4cef-ab17-b4c847d1b57a" } ] }
SNS
続いてDead Letter Queueの宛先としてSNSを指定します。以下のファイルを用意してください。
serverless.yml
frameworkVersion: ">=1.6.0" service: lambda-dlq-sns-test custom: sns: LambdaDLQSNSTest provider: name: aws runtime: python2.7 stage: dev region: ap-northeast-1 iamRoleStatements: - Effect: Allow Action: - sns:Publish Resource: - Ref: ${self:custom.sns} plugins: - serverless-plugin-lambda-dead-letter functions: fail: handler: handler.fail deadLetter: targetArn: GetResourceArn: ${self:custom.sns} events: - schedule: rate(1 minute) invoked: handler: handler.invoked events: - sns: arn:aws:sns:${self:provider.region}:${opt:account}:${self:custom.sns} resources: Resources: LambdaDLQSNSTest: Type: AWS::SNS::Topic Properties: TopicName: ${self:custom.sns}
今回はLambda関数の実行に失敗した場合SNSのトピックに通知するので sns:Publish
権限を付与しています。この設定をしないと以下のようにエラーが出力されます。
Serverless Error --------------------------------------- The provided execution role does not have permissions to call Publish on SNS
24から34行目でLambda関数を定義しています。今回はDead Letter Queueに指定したSNSから別のLambda関数を実行させているので計2つのLambda関数( fail
及び invoked
)を指定して、 fail
にDead Letter Queueの設定を、 invoked
にSNSのトピックをトリガーに指定しています。今回、Dead Letter Queueuの設定は resources
プロパティで作成したSNSトピックを GetResourceArn
でARNを取得させています。本来であれば Ref
関数をこのコンテキストで使えばよいかと思いますが、恐らく現状使えないようなのでこういった少々回りくどい設定(独自プロパティの定義)になっているのかと推測します。
handler.py
from __future__ import print_function def fail(event, context): raise Exception('Exception occured') def invoked(event, context): print('Invoked with the event: {}'.format(event))
Lambda関数では fail
及び invoked
を定義しています。
${opt:account}
でコマンドライン引数からAWSアカウントIDを取得する処理にしているので、デプロイする際には以下のようにして引数を渡してください。
$ sls deploy -v \ --account "$(aws sts get-caller-identity \ --query 'Account' \ --output text)" Serverless: Packaging service... Serverless: Uploading CloudFormation file to S3... Serverless: Uploading service .zip file to S3 (190.79 KB)... <snip>
動作確認はSNSトピックからInvokeされるLambda関数のCloudWatch Logsを眺めて実行されるかどうかで確認してみます。以下のコマンドをしばらく実行させておくとログが標準出力に表示されると思います。
$ sls logs -f invoked -t \ --account "$(aws sts get-caller-identity \ --query 'Account' \ --output text)" START RequestId: 258fb904-e7bd-11e6-8365-a7da3782ec42 Version: $LATEST Invoked with the event: {u'Records': [{u'EventVersion': u'1.0', u'EventSubscriptionArn': u'arn:aws:sns:ap-northeast-1:************:LambdaDLQSNSTest:23992f8f-5d52-4822-8085-516d209126da', u'EventSource': u'aws:sns', u'Sns': {u'SignatureVersion': u'1', u'Timestamp': u'2017-01-31T13:57:04.578Z', u'Signature': u'ezCxtZGdK+NHtk4dWGsVyWNjas6URrhZAjd9YMKei3uZypQteH9g8tOQum0gFCotMB132xwXjoVh9Q44xq/VX5PMb+bj/3UCw/dBHxT0zJvphe1WzpUCUmXh0m/LbLg3G+wgYjppoBtwLzkf9bE+aJiWu/1UsBaUuVdmSOy1Jg6QjlFbr7JiTERKGj6AjFcIslwzrZPVkxIyK5mTCi5eQd3KzDRt07djXOc7BWMXyE9gkEG4HM7dNVzSSpTXWVpdC4KHixylzY6sVp97+xffFkEtSbMUZq4/DsThfPq9gnCZaEu3ZGsmzhg4a0sWfRvjBhOaacOvaM1DI9Wips8gkg==', u'SigningCertUrl': u'https://sns.ap-northeast-1.amazonaws.com/SimpleNotificationService-b95095beb82e8f6a046b3aafc7f4149a.pem', u'MessageId': u'92d35e75-9cac-5b1c-b569-0f7f055c5c18', u'Message': u'{"version":"0","id":"44284c7d-b6b2-46dd-baa6-d8901c25619a","detail-type":"Scheduled Event","source":"aws.events","account":"************","time":"2017-01-31T13:53:30Z","region":"ap-northeast-1","resources":["arn:aws:events:ap-northeast-1:************:rule/lambda-dlq-sns-test-dev-FailEventsRuleSchedule1-1PH4WQ9GK4EUS"],"detail":{}}', u'MessageAttributes': {u'ErrorCode': {u'Type': u'String', u'Value': u'200'}, u'ErrorMessage': {u'Type': u'String', u'Value': u'Exception occured'}, u'RequestID': {u'Type': u'String', u'Value': u'b928907b-e7bc-11e6-9b02-8324f167199c'}}, u'Type': u'Notification', u'UnsubscribeUrl': u'https://sns.ap-northeast-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=arn:aws:sns:ap-northeast-1:************:LambdaDLQSNSTest:23992f8f-5d52-4822-8085-516d209126da', u'TopicArn': u'arn:aws:sns:ap-northeast-1:************:LambdaDLQSNSTest', u'Subject': None}}]} END RequestId: 258fb904-e7bd-11e6-8365-a7da3782ec42 REPORT RequestId: 258fb904-e7bd-11e6-8365-a7da3782ec42 Duration: 0.39 ms Billed Duration: 100 ms Memory Size: 1024 MB Max Memory Used: 16 MB <snip>
まとめ
いかがだったでしょうか。
Serverless Frameworkのプラグインを利用したDead Letter Queueの設定方法をご紹介しました。今回ご紹介した以外にもさまざまなプラグインが有志の方によって公開されています。品質はものによってだいぶ変わってくるのですが、今回ご紹介したプラグインはかなり安定して動作するなという印象です。一度利用されてみることをオススメします。
本エントリがみなさんの参考になれば幸いに思います。